package cn.comtom.ewbs.signature.service.impl;

import java.io.File;
import java.nio.file.AccessDeniedException;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;

import cn.comtom.ewbs.signature.common.exception.SignException;
import cn.comtom.ewbs.signature.common.vo.request.CertApplyReq;
import cn.comtom.ewbs.signature.common.vo.response.CertResp;
import cn.comtom.ewbs.signature.entity.SignDev;
import cn.comtom.ewbs.signature.mapper.SignDevMapper;
import cn.comtom.ewbs.signature.service.AbstractSignService;
import cn.comtom.ewbs.signature.service.ISignatureService;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.tass.exceptions.YJException;
import lombok.extern.slf4j.Slf4j;

@Service("sign")
@Slf4j
public class SignatureServiceImpl extends AbstractSignService implements ISignatureService{

	public static final String linux_so_path = "/data/apps/jar/"; // so库文件路径
	public static final String win_so_path = "/so/"; // so库文件路径
	
	public static final String win_path1 = "C:/Users/Public/tasslibs/"; // sjj1303/sjj1313/sjj1507系统动态库目录
	public static final String win_path2 = "C:/nfast/etc/"; // srj1401系统动态库目录
	
	private static final String linux_path = "/usr/etc/tasslibs/"; // sjj1303/sjj1313/sjj1507系统动态库目录
	private static final String amd64_path = "/opt/jdk/lib/amd64/"; // jdk库目录

	private static AbstractSignService signService;
	
	@Autowired
	private Map<String,AbstractSignService> signMapService;
	
	@Autowired
	private SignDevMapper signDevMapper;
	
	/**
	 * 根据签名方式复制对应so文件到系统库目录
	 * 
	 * @param type
	 */
	@Override
	public  boolean initSignDev(String type) {
		LambdaQueryWrapper<SignDev> wrapper = Wrappers.lambdaQuery();
		if(StrUtil.isBlank(type)) {
			wrapper.eq(SignDev::getDevStatus, 0);
		}else {
			wrapper.eq(SignDev::getDevName, type);
		}
		SignDev sd = signDevMapper.selectOne(wrapper);
		if(sd == null) {
			return false;
		}
		type = sd.getDevName();
		AbstractSignService.signType = sd.getDevName();
		AbstractSignService.dataType = sd.getDataType();
		log.info("use {} system, signType:{},dataType:{}",AbstractSignService.isWindows?"windows":"linux", signType,dataType);
		String linuxSoPath = linux_so_path.concat(type);
		String winSoPath = getProjectPath().concat(win_so_path).concat(type);
		if(AbstractSignService.isWindows) {
			FileUtil.mkdir(win_path1);
			FileUtil.mkdir(win_path2);
			if (FileUtil.exist(winSoPath)) {
				File[] files = FileUtil.ls(winSoPath);
				List<File> fileList = Lists.newArrayList(files);
				if (CollectionUtil.isNotEmpty(fileList))
					fileList.forEach(f -> {
						try {
							FileUtil.copy(f, new File(win_path1), true);
							FileUtil.copy(f, new File(win_path2), true);
						} catch (Exception e) {
							log.warn("复制库文件异常-{}",e.getMessage());
						}
					});
			}
		}else {
			if (FileUtil.exist(linuxSoPath)) {
				File[] files = FileUtil.ls(linuxSoPath);
				List<File> fileList = Lists.newArrayList(files);
				if(!FileUtil.isDirectory(linux_path)){
					FileUtil.mkdir(linux_path);
				}
				if (CollectionUtil.isNotEmpty(fileList))
					fileList.forEach(f -> {
						try {
							FileUtil.copy(f, new File(linux_path), true);
							FileUtil.copy(f, new File(amd64_path), true);
						} catch (Exception e) {
							log.warn("复制库文件异常-{}",e.getMessage());
						}
					});
			}
		}
		//打开设备
		signService =  signMapService.get(signType);
		if(signService!=null) {
			return signService.openDevice();
		}
		return false;
	}

	@Override
	public String getFileSign(byte[] data) {
		String xmlSign = "";
		try {
			xmlSign = signService.getFileSign(data);
			log.info("use {} getFileSign xmlsign:{}", signType, xmlSign);
		} catch (Exception e) {
			log.error("use {} getFileSign failed. ", signType, e);
			throw new SignException("签名失败,正在重试,重试3次任然失败则重启签名服务！");
		}
		return xmlSign;
	}

	@Override
	public Boolean verifyFileSign(byte[] data, String signValue) throws YJException {
		try {
			boolean result = signService.verifyFileSign(data, signValue);
			log.info("use {} 验证签名结果  :{}", signType, result);
			return result;
		} catch (Exception e) {
			log.error("use {} verifyFileSign  failed. ", signType, e);
			return false;
		}
	}

	@Override
	public String getByteSign(byte[] data) {
		String xmlSign = "";
		try {
			xmlSign = signService.getByteSign(data);
			log.info("use {} getSign xmlsign:{}", signType, xmlSign);
		} catch (Exception e) {
			log.error("use {} getFileSign failed. ", signType, e);
			throw new SignException("签名失败,正在重试,重试3次任然失败则重启签名服务！");
		}
		return xmlSign;
	}

	/**
	 * 验证签名
	 *
	 * @return boolean
	 * @throws YJException
	 */
	public Boolean verifyByteSign(byte[] data, String signValue) throws YJException {
		try {
			boolean result = signService.verifyByteSign(data, signValue);
			log.info("use {} 验证签名结果  :{}", signType, result);
			return result;
		} catch (Exception e) {
			log.error("use {} verifySign  failed. ", signType, e);
			return false;
		}
	}

	/**
	 * 打开密码机
	 *
	 * @param flag
	 */
	public boolean openDevice() {
		try {
			log.info("use {} 打开密码器", signType);
			return signService.openDevice();
		} catch (Exception e) {
			e.printStackTrace();
			log.error("Signature helper close device failed.", e);
			return false;
		}
	}

	/**
	 * 关闭密码机
	 */
	public void closeDevice() {
		try {
			log.info("use {} 关闭密码器，", signType);
			// 关闭sjj1507密码机
			signService.closeDevice();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	//@Retryable(value = { RuntimeException.class }, maxAttempts = 3, backoff = @Backoff(delay = 500, multiplier = 1))
	public CertResp certApply(CertApplyReq certApplyReq) {
		CertResp certResp = new CertResp();
		try {
			certResp = signService.certApply(certApplyReq);
			log.info("use {} 向安全代理获取信任列表，params:{},result:{}", JSON.toJSONString(certApplyReq),
					JSON.toJSONString(certResp));
		} catch (Exception e) {
			log.error("use {} 向安全代理获取信任列表异常，params:{},result:{}", signType, JSON.toJSONString(certApplyReq));
			e.printStackTrace();
			throw new SignException("获取信任列表失败,正在重试,重试3次任然失败则重启签名服务！");
		}
		return certResp;
	}

	public void restart() throws Exception {
		closeDevice();
		openDevice();
	}

	@Override
	public Boolean importCert(List<String> certs) {
		
		return signService.importCert(certs);
	}

	@Override
	public Boolean importCertauthList(String certauthList) {
		
		return signService.importCertauthList(certauthList);
	}

}
